package com.triones.api.service.interlace.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.annotation.Master;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.config.InterlaceConfig;
import com.ruoyi.common.utils.SnCreator;
import com.triones.api.entity.interlace.bo.request.ListAllBalancesRequest;
import com.triones.api.entity.interlace.dto.*;
import com.triones.api.entity.interlace.vo.InterlaceMemberVO;
import com.triones.api.mapper.CardMgrFeeMapper;
import com.triones.api.mapper.interlace.*;
import com.triones.api.service.interlace.InterlaceCommunalService;
import com.triones.api.service.interlace.InterlaceCryptoService;
import com.triones.api.service.interlace.InterlaceFiatService;
import com.triones.api.service.third.InterlaceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * interlace 共有方法
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InterlaceCommunalServiceImpl implements InterlaceCommunalService {

    private final InterlaceService interlaceService;

    private final InterlaceConfig interlaceConfig;

    private final InterlaceMemberMapper interlaceMemberMapper;

    private final InterlaceBalancesMapper interlaceBalancesMapper;

    private final MasterBalanceMapper masterBalanceMapper;

    private final InterlaceQuantumTransferMapper interlaceQuantumTransferMapper;

    @Override
    public void updateBalances(ListAllBalancesRequest request) {
        Long uid = null;
        InterlaceMemberVO memberVO = interlaceMemberMapper.selectVoOne(new LambdaQueryWrapper<InterlaceMemberDO>()
            .eq(InterlaceMemberDO::getInterlaceAccountId, request.getAccountId()));
        if (memberVO != null) {
            uid = memberVO.getId();
        }
        Map mapResponse = interlaceService.listAllBalances(request);
        if (mapResponse != null) {
            List<Map> response = (List<Map>) mapResponse.get("data");
            List<InterlaceBalancesDO> addList = new ArrayList<>();
            List<InterlaceBalancesDO> editList = new ArrayList<>();
            if (response != null && response.size() > 0) {
                for (Map map : response) {
                    InterlaceBalancesDO balancesDO = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
                        .eq(InterlaceBalancesDO::getBid, Convert.toStr(map.get("id")))
                        .last("FOR UPDATE"));
                    if (balancesDO != null) {
                        balancesDO.setAvailable(Convert.toBigDecimal(map.get("available")));
                        balancesDO.setPending(Convert.toBigDecimal(map.get("pending")));
                        balancesDO.setFrozen(Convert.toBigDecimal(map.get("frozen")));
                        balancesDO.setUpdateTime(System.currentTimeMillis());
                        balancesDO.setWalletType(Convert.toStr(map.get("walletType")));
                        editList.add(balancesDO);
                    } else {
                        balancesDO = new InterlaceBalancesDO();
                        balancesDO.setUid(uid);
                        balancesDO.setInterlaceAccountId(Convert.toStr(map.get("accountId")));
                        balancesDO.setBid(Convert.toStr(map.get("id")));
                        balancesDO.setAvailable(Convert.toBigDecimal(map.get("available")));
                        balancesDO.setPending(Convert.toBigDecimal(map.get("pending")));
                        balancesDO.setFrozen(Convert.toBigDecimal(map.get("frozen")));
                        balancesDO.setCurrency(Convert.toStr(map.get("currency")));
                        balancesDO.setWalletType(Convert.toStr(map.get("walletType")));
                        balancesDO.setCreateTime(System.currentTimeMillis());
                        balancesDO.setUpdateTime(System.currentTimeMillis());
                        balancesDO.setVirtualAvailable(BigDecimal.ZERO);
                        balancesDO.setVirtualPending(BigDecimal.ZERO);
                        balancesDO.setVirtualFrozen(BigDecimal.ZERO);
                        addList.add(balancesDO);
                    }
                }
                if (addList.size() > 0) {
                    interlaceBalancesMapper.insertBatch(addList);
                }
                if (editList.size() > 0) {
                    interlaceBalancesMapper.updateBatchById(editList);
                }
            }
        }
    }

    @Override
    public void updateMasterBalances(ListAllBalancesRequest request) {
        Map mapResponse = interlaceService.listAllBalances(request);
        if (mapResponse != null) {
            List<Map> response = (List<Map>) mapResponse.get("data");
            List<MasterBalanceDO> editList = new ArrayList<>();
            if (response != null && response.size() > 0) {
                for (Map map : response) {
                    MasterBalanceDO masterBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
                        .eq(MasterBalanceDO::getBid, Convert.toStr(map.get("id")))
                        .last("FOR UPDATE"));
                    if (masterBalance != null) {
                        masterBalance.setAvailable(Convert.toBigDecimal(map.get("available")));
                        masterBalance.setPending(Convert.toBigDecimal(map.get("pending")));
                        masterBalance.setFrozen(Convert.toBigDecimal(map.get("frozen")));
                        masterBalance.setWalletType(Convert.toStr(map.get("walletType")));
                        masterBalance.setUpdateTime(System.currentTimeMillis());
                        editList.add(masterBalance);
                    }
                }
                if (editList.size() > 0) {
                    masterBalanceMapper.updateBatchById(editList);
                }
            }
        }
    }

    @Override
    public Boolean checkBalances(InterlaceBalancesDO dto, BigDecimal expenditure) {
        boolean flag = false;
        /** 发起请求 */
        if ("Budget".equals(dto.getWalletType())) {
            if (Convert.toBigDecimal(dto.getAvailable()).compareTo(expenditure) >= 0) {
                flag = true;
            }
        } else {
            if (Convert.toBigDecimal(dto.getVirtualAvailable(), BigDecimal.ZERO).compareTo(expenditure) >= 0) {
                flag = true;
            }
        }
        return flag;
    }

    @Override
    public InterlaceQuantumTransferDO addQuantumTransfer(InterlaceQuantumTransferDO quantumTransferDO) {
        /** 记录量子账户 */
        InterlaceBalancesDO balancesDO = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
            .eq(InterlaceBalancesDO::getInterlaceAccountId, quantumTransferDO.getAccountId())
            .eq(InterlaceBalancesDO::getUid, quantumTransferDO.getUid())
            .eq(InterlaceBalancesDO::getCurrency, "USD")
            .eq(InterlaceBalancesDO::getWalletType, "QuantumAccount")
            .last("FOR UPDATE"));
        if (balancesDO != null) {
            quantumTransferDO.setBalancesId(balancesDO.getBid());
        }
        quantumTransferDO.setSn(SnCreator.generateQTSn());
        interlaceQuantumTransferMapper.insert(quantumTransferDO);
        return quantumTransferDO;
    }

    @Override
    public void updateCryptoWallet(String subAccountId, String currency, BigDecimal amount, String type) {
        /** 更新子加密钱包 */
        InterlaceBalancesDO subBalances = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
            .eq(InterlaceBalancesDO::getInterlaceAccountId, subAccountId)
            .eq(InterlaceBalancesDO::getWalletType, "CryptoAsset")
            .eq(InterlaceBalancesDO::getCurrency, currency)
            .last("limit 1 FOR UPDATE"));

        /** 更新主加密钱包 */
        MasterBalanceDO masterBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
            .eq(MasterBalanceDO::getAccountId, interlaceConfig.getMasterAccount())
            .eq(MasterBalanceDO::getWalletType, "CryptoAsset")
            .eq(MasterBalanceDO::getCurrency, currency)
            .last("limit 1 FOR UPDATE"));

        if ("increase".equals(type)) {
            if (subBalances != null) {
                interlaceBalancesMapper.increaseVirtualAvailable(subBalances.getId(),amount,System.currentTimeMillis());

            }
            if (masterBalance != null) {
                masterBalanceMapper.increaseVirtualAvailable(masterBalance.getId(),amount,System.currentTimeMillis());
            }
        }
        if ("decrease".equals(type)) {
            if (subBalances != null) {
                interlaceBalancesMapper.decreaseVirtualAvailable(subBalances.getId(),amount,System.currentTimeMillis());
            }
            if (masterBalance != null) {
                masterBalanceMapper.decreaseVirtualAvailable(masterBalance.getId(),amount,System.currentTimeMillis());
            }
        }
    }
}
